package com.itcast.netty.utils;

import com.itcast.common.entity.MethodInvokeMeta;
import com.itcast.common.exception.NoUsedChannelException;
import io.netty.channel.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListSet;

/**
 * 通道工具类
 *
 * @author eternity
 */
public class ChannelUtils {
    /**
     * 日志输出
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(ChannelUtils.class);

    /**
     * 用于记录CS连接后建立的通道
     */
    private static final Set<Channel> CHANNELS = new ConcurrentSkipListSet<>();

    /**
     * 用于记录通道响应的结果集
     */
    private static final Map<String, Object> RESULT_MAP = new ConcurrentHashMap<>();

    private ChannelUtils() {
    }

    /**
     * 获取回调结果
     *
     * @param invokeMeta 远程调用方法信息
     * @param key        用于取结果的key值
     */
    public static void remoteCall(MethodInvokeMeta invokeMeta, String key) {
        LOGGER.info("{} -> [远程调用]", ChannelUtils.class.getName());
        Iterator<Channel> iterator = CHANNELS.iterator();
        Channel channel;
        if (iterator.hasNext()) {
            channel = iterator.next();
        } else {
            LOGGER.error("{} -> [没有活跃的通道]", ChannelUtils.class);
            throw new NoUsedChannelException("没有活跃的通道");
        }
        // 将用于获取结果的key保存,以通道id为键
        String channelId = channel.id().asLongText();
        LOGGER.info("{} -> [保存获取结果的key] key - {} 通道id - {}", ChannelUtils.class, key, channelId);
        RESULT_MAP.put(channelId, key);
        channel.writeAndFlush(invokeMeta);
    }

    /**
     * 移除通道
     *
     * @param channel 通道
     */
    public static void remove(Channel channel) {
        CHANNELS.remove(channel);
    }

    /**
     * 注册通道
     *
     * @param channel 通道
     */
    public static void registerChannel(Channel channel) {
        LOGGER.info("{} -> [添加通道] {}", ChannelUtils.class.getName(), channel.id());
        CHANNELS.add(channel);
    }

    /**
     * 获取结果集的key
     *
     * @param key 保存的唯一标识
     * @return 结果集的 key (通道标识)
     */
    public static String getResultKey(String key) {
        return (String) getResult(key);
    }

    /**
     * 根据结果集的 key 获取结果集
     *
     * @param key 结果集的key
     * @return 结果集
     */
    public static Object getResult(String key) {
        return RESULT_MAP.get(key);
    }

    /**
     * 计算结果集（存储响应结果）
     *
     * @param key   唯一标识
     * @param value 结果集
     */
    public static void calculateResult(String key, Object value) {
        RESULT_MAP.put(key, value);
    }
}
